package com.ruoyi.app.service;

import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.secure.BCrypt;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.google.gson.Gson;
import com.ruoyi.app.domain.bo.AppUserBo;
import com.ruoyi.app.domain.entity.AppUser;
import com.ruoyi.app.domain.vo.AppUserVo;
import com.ruoyi.app.mapper.AppUserMapper;
import com.ruoyi.common.core.constant.Constants;

import com.ruoyi.common.core.domain.bo.WxLoginUser;

import com.ruoyi.common.core.enums.DeviceType;
import com.ruoyi.common.core.enums.UserStatus;

import com.ruoyi.common.core.utils.*;
import com.ruoyi.common.json.utils.JsonUtils;
import com.ruoyi.common.log.event.LogininforEvent;
import com.ruoyi.common.satoken.utils.LoginHelper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.MultiValueMap;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.http.HttpEntity;
import org.springframework.http.ResponseEntity;

import java.io.UnsupportedEncodingException;
import java.util.Map;

/**
 * 登录校验方法
 *
 * @author Lion Li
 */
@RequiredArgsConstructor
@Slf4j
@Service
public class AppLoginService {

    private final AppUserMapper appUserMapper;
    private final AppUserService appUserService;

    private static final String APPID = "wx9d47fdd9b6e89cce";
    // 配置文件中获取的微信公众号appSecret
    private static final String APPSECRET = "d0ee22a57745d553e204f22c410511b7";

    public String wxLogin(String code) {
        // xcxCode 为 小程序调用 wx.login 授权后获取
        // todo 以下自行实现
        // 校验 appid + appsrcret + xcxCode 调用登录凭证校验接口 获取 session_key 与 openid
        RestTemplate restTemplate = new RestTemplate();
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("appid", APPID);
        map.add("secret", APPSECRET);
        map.add("code", code);
        map.add("grant_type", "authorization_code");

        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(
            "https://api.weixin.qq.com/sns/oauth2/access_token", request, String.class);

        // 解析返回结果获取openid（这里简单示例，实际需要更严谨的解析）
        String openid = null;
        String access_token = null;
        if (response.getStatusCode().is2xxSuccessful()) {
            String responseBody = response.getBody();
            System.out.println(responseBody);
            Map<String, Object> Map = JsonUtils.parseMap(responseBody);
            // 假设返回结果是JSON格式，解析出openid（实际可能需要使用JSON解析库）
            openid  = (String) Map.get("openid");
            access_token  = (String) Map.get("access_token");
        }
        if(openid==null||access_token==null){
            return null;
        }
        RestTemplate restTemplates = new RestTemplate();
        HttpHeaders headerss = new HttpHeaders();
        headerss.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        MultiValueMap<String, String> maps = new LinkedMultiValueMap<>();

        HttpEntity<MultiValueMap<String, String>> requests = new HttpEntity<>(maps, headerss);
        ResponseEntity<String> responses = restTemplates.postForEntity(
            "https://api.weixin.qq.com/sns/userinfo"+"?access_token="+access_token+"&openid="+openid+"&lang=zh_CN", requests, String.class
            , requests, String.class);
        String nickname = "";
        String sex = "";
        String language = "";
        String city  = "";
        String province = "";
        String country  = "";
        String headimgurl = "";
        if (responses.getStatusCode().is2xxSuccessful()) {
            String responseBodys = responses.getBody();
            System.out.println(responseBodys);
            Map<String, Object> jsonMap = JsonUtils.parseMap(responseBodys);
            // 解析出openid（这里简单示例，实际可能需要使用JSON解析库更严谨地解析）
            openid  = (String) jsonMap.get("openid");
            nickname  = (String) jsonMap.get("nickname");
            sex = String.valueOf(jsonMap.get("sex"));
            language = (String) jsonMap.get("language");
            city= (String) jsonMap.get("city");
            province = (String) jsonMap.get("province");
            country= (String) jsonMap.get("country");
            headimgurl= (String) jsonMap.get("headimgurl");
        }
        // 框架登录不限制从什么表查询 只要最终构建出 LoginUser 即可
        AppUserVo user = loadUserByOpenid(openid);
        if(user==null){
            AppUserBo bo = new AppUserBo();
            if(nickname!=null){
            try {
                byte[] bytes = nickname.getBytes("ISO-8859-1"); // 将昵称转换为ISO-8859-1编码
                nickname = new String(bytes, "UTF-8"); // 将编码转换为UTF-8
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            }
            bo.setNickName(nickname);
            bo.setOpenid(openid);
            bo.setAvatar(headimgurl);
            bo.setSex(sex);
            bo.setArea(city+province+country);
            bo.setStatus("1");
            bo.setUserName(nickname);
            appUserService.insertByBo(bo);
            user = loadUserByOpenid(openid);
        }else {
            AppUserBo bo = new AppUserBo();
            if(nickname!=null){
                try {
                    byte[] bytes = nickname.getBytes("ISO-8859-1"); // 将昵称转换为ISO-8859-1编码
                    nickname = new String(bytes, "UTF-8"); // 将编码转换为UTF-8
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                }
            }
            bo.setNickName(nickname);
            bo.setOpenid(openid);
            bo.setAvatar(headimgurl);
            bo.setSex(sex);
            bo.setArea(city+province+country);
            bo.setUserId(user.getUserId());
            bo.setUserName(nickname);
            appUserService.updateByBo(bo);
            user = loadUserByOpenid(openid);
        }
        // 此处可根据登录用户的数据不同 自行创建 loginUser 属性不够用继承扩展就行了
        WxLoginUser loginUser = new WxLoginUser();
        if(user==null){
            return null;
        }
        loginUser.setUserId(user.getUserId());
        loginUser.setOpenid(openid);
        // 生成token
        LoginHelper.wxloginByDevice(loginUser, DeviceType.WX);

        recordLogininfor(user.getUserName(), Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"));
        recordLoginInfo(user.getUserId(), user.getUserName());
        return StpUtil.getTokenValue();
    }


    /**
     * 记录登录信息
     *
     * @param username 用户名
     * @param status   状态
     * @param message  消息内容
     */
    private void recordLogininfor(String username, String status, String message) {
        LogininforEvent logininforEvent = new LogininforEvent();
        logininforEvent.setUsername(username);
        logininforEvent.setStatus(status);
        logininforEvent.setMessage(message);
        logininforEvent.setRequest(ServletUtils.getRequest());
        SpringUtils.context().publishEvent(logininforEvent);
    }

    private AppUserVo loadUserByOpenid(String openid) {
        // 使用 openid 查询绑定用户 如未绑定用户 则根据业务自行处理 例如 创建默认用户
        // todo 自行实现 userService.selectUserByOpenid(openid);
        AppUserVo user = appUserMapper.selectVoOne(new LambdaQueryWrapper<AppUser>().eq(AppUser::getOpenid, openid));
        if (ObjectUtil.isNull(user)) {
            log.info("登录用户：{} 不存在.", openid);
            // todo 用户不存在 业务逻辑自行实现
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", openid);
            // todo 用户已被停用 业务逻辑自行实现
        }
        return user;
    }

    /**
     * 记录登录信息
     *
     * @param userId 用户ID
     */
    public void recordLoginInfo(Long userId, String username) {
        AppUser sysUser = new AppUser();
        sysUser.setUserId(userId);
        sysUser.setLoginIp(ServletUtils.getClientIP());
        sysUser.setLoginDate(DateUtils.getNowDate());
        sysUser.setUpdateBy(username);
        appUserMapper.updateById(sysUser);
    }
}
